/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// Copyright tang.  All rights reserved.
// https://gitee.com/inrgihc/dbswitch
//
// Use of this source code is governed by a BSD-style license
//
// Author: tang (inrgihc@126.com)
// Date : 2020/1/2
// Location: beijing , china
/////////////////////////////////////////////////////////////
package com.je.meta.service.dbswitch.service.impl.database;

import com.je.meta.model.database.ColumnDescription;
import com.je.meta.model.database.ColumnMetaData;
import com.je.meta.model.database.TableDescription;
import com.je.meta.model.database.type.ProductTypeEnum;
import com.je.meta.service.dbswitch.common.constant.Const;
import com.je.meta.service.dbswitch.service.AbstractDatabase;
import com.je.meta.service.dbswitch.service.IDatabaseInterface;
import com.je.meta.util.database.DDLFormatterUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;

/**
 * 支持SQLite数据库的元信息实现
 *
 * @author tang
 */
public class DatabaseSqliteImpl extends AbstractDatabase implements IDatabaseInterface {

    public DatabaseSqliteImpl() {
        super("org.sqlite.JDBC");
    }

    @Override
    public ProductTypeEnum getDatabaseType() {
        return ProductTypeEnum.SQLITE3;
    }

    @Override
    public List<String> querySchemaList(Connection connection) {
        return Collections.singletonList("main");
    }

    @Override
    public String getTableDDL(Connection connection, String schemaName, String tableName) {
        String sql = "SELECT sql FROM \"sqlite_master\" where type='table' and tbl_name=? ";
        try (PreparedStatement ps = connection.prepareStatement(sql)) {
            ps.setString(1, tableName);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs != null && rs.next()) {
                    return DDLFormatterUtils.format(rs.getString(1));
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

    @Override
    public String getViewDDL(Connection connection, String schemaName, String tableName) {
        String sql = "SELECT sql FROM \"sqlite_master\" where type='view' and tbl_name=? ";
        try (PreparedStatement ps = connection.prepareStatement(sql)) {
            ps.setString(1, tableName);
            try (ResultSet rs = ps.executeQuery()) {
                if (rs != null && rs.next()) {
                    return DDLFormatterUtils.format(rs.getString(1));
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

    @Override
    public List<ColumnDescription> querySelectSqlColumnMeta(Connection connection, String sql) {
        String querySQL = String.format(" %s LIMIT 0 ", sql.replace(";", ""));
        return this.getSelectSqlColumnMeta(connection, querySQL);
    }

    @Override
    protected String getTableFieldsQuerySQL(String schemaName, String tableName) {
        return String.format("SELECT * FROM \"%s\".\"%s\"  ", schemaName, tableName);
    }

    @Override
    protected String getTestQuerySQL(String sql) {
        return String.format("explain %s", sql.replace(";", ""));
    }

    @Override
    public String getFieldDefinition(ColumnMetaData v, List<String> pks, boolean useAutoInc,
                                     boolean addCr, boolean withRemarks) {
        String fieldname = v.getName();
        int length = v.getLength();
        int precision = v.getPrecision();
        int type = v.getType();

        String retval = " \"" + fieldname + "\"   ";

        switch (type) {
            case ColumnMetaData.TYPE_TIMESTAMP:
            case ColumnMetaData.TYPE_TIME:
            case ColumnMetaData.TYPE_DATE:
                // sqlite中没有时间数据类型
                retval += "DATETIME";
                break;
            case ColumnMetaData.TYPE_BOOLEAN:
                retval += "CHAR(1)";
                break;
            case ColumnMetaData.TYPE_NUMBER:
            case ColumnMetaData.TYPE_INTEGER:
            case ColumnMetaData.TYPE_BIGNUMBER:
                if (null != pks && !pks.isEmpty() && pks.contains(fieldname)) {
                    // 关键字 AUTOINCREMENT 只能⽤于整型（INTEGER）字段。
                    if (useAutoInc) {
                        retval += "INTEGER PRIMARY KEY AUTOINCREMENT";
                    } else {
                        retval += "BIGINT ";
                    }
                } else {
                    if (precision != 0 || length < 0 || length > 18) {
                        retval += "NUMERIC";
                    } else {
                        retval += "INTEGER";
                    }
                }
                break;
            case ColumnMetaData.TYPE_STRING:
                if (length < 1 || length >= AbstractDatabase.CLOB_LENGTH) {
                    retval += "BLOB";
                } else {
                    retval += "TEXT";
                }
                break;
            case ColumnMetaData.TYPE_BINARY:
                retval += "BLOB";
                break;
            default:
                retval += "TEXT";
                break;
        }

        if (addCr) {
            retval += Const.CR;
        }

        return retval;
    }

    @Override
    public List<String> getTableColumnCommentDefinition(TableDescription td,
                                                        List<ColumnDescription> cds) {
        return Collections.emptyList();
    }

}
